class Operation < ActiveRecord::Base

  belongs_to :shares,
         :foreign_key => :share_id
  belongs_to :accounts,
         :foreign_key => :account_id

  has_and_belongs_to_many :sell,
     :class_name => 'Operation',
     :association_foreign_key => 'operation_sell_id',
     :join_table => 'operation_sell'

  validates_presence_of :timestamp, :share_id, :quantity, :price, :account_id
  validates_numericality_of :quantity, :price

  def sold
    is_open == 'f'
  end

  def self.list
    find(:all,
         :conditions => "operation_type='B' and is_open='t'",
         :order => "is_open desc, timestamp")
  end
  def self.historyList
    find(:all,
         :conditions => "operation_type='B' and is_open='f'",
         :order => "is_open desc, timestamp")
  end

  def total
    result = Operation.new
    result.quantity = 0
    if (@sell != nil)
      for s in @sell
        result.quantity += s.quantity
        result.net_amount += s.net_amount
        result.brokerage += s.brokerage
        result.gross_amount += s.gross_amount
      end
    end
    result.quantity = quantity - result.quantity
    result.net_amount = result.net_amount - net_amount
    result.brokerage = brokerage + result.brokerage
    result.gross_amount = result.gross_amount - gross_amount
    result
  end

  def zeroPrice
    tot = total
    accounts.calculateZeroPrice(-tot.gross_amount, tot.quantity)
  end

  def zeroPercentage
    tot = total
    logger.info(tot.inspect)
    (((accounts.calculateZeroPrice(-tot.gross_amount, tot.quantity)*tot.quantity) - (-tot.net_amount))/(-tot.net_amount))*100
  end

  def simulateSelling(params)
    if (params[:price])
      price = params[:price]
      timestamp = Date.new
    else
      stockValue = StockPriceProviderFactory.getStockPriceProvider.stockValueFor(shares.name)
      price = stockValue.getPrice
      timestamp = stockValue.getDate
    end
    quantity = (params[:quantity] ? params[:quantity] : quantity_to_sell)
    result = Operation.newforsell(self, {:quantity => quantity, :price => price})
    result.timestamp = timestamp
    result
  end

  def simulateIncomeOutcome(simulatedSell)
    result = self.deep_clone
    result.net_amount = 0
    result.gross_amount = 0
    result.brokerage = 0
    result.quantity = 0
    if (sell != nil)
      for s in sell
        result.quantity += s.quantity
        result.net_amount += s.net_amount
        result.brokerage += s.brokerage
        result.gross_amount += s.gross_amount
      end
    end
    result.quantity += simulatedSell.quantity
    result.net_amount += simulatedSell.net_amount
    result.brokerage += simulatedSell.brokerage
    result.gross_amount += simulatedSell.gross_amount

    result.price = simulatedSell.price
    result
  end

  def simulateTotal(simulatedSell)
    result = self.total
    result.brokerage += simulatedSell.brokerage
    result.net_amount += simulatedSell.net_amount
    result.gross_amount += simulatedSell.gross_amount

    result.price = simulatedSell.price
    result
  end

  def currentValue(price)
    result = self.deep_clone
    result
  end

  def quantity_to_sell
    sold = 0
    if (self.sell != nil)
      for s in self.sell
        sold += s.quantity
      end
    end
    quantity - sold
  end


  def self.newforbuy(params)
    result = new(params)
    result.operation_type="B"
    result.is_open='t'
    result.net_amount = result.price*result.quantity
    result.brokerage = result.accounts.calculateBrokerage(result.net_amount)
    result.gross_amount = result.net_amount + result.brokerage
    result
  end


  def self.newforsell(bought, params)
    result = new(params)
    result.accounts = bought.accounts
    result.shares = bought.shares
    result.operation_type="S"
    result.net_amount = result.price*result.quantity
    result.brokerage = result.accounts.calculateBrokerage(result.net_amount)
    result.gross_amount = result.net_amount - result.brokerage

    total = bought.total
    if (total.quantity < result.quantity)
      result.id = bought.id
      result.errors.add(:quantity, "You can't sell more than you bought!.")
    end

    result
  end

  def self.buy(buy)
    transaction(buy) do
      buy.save
    end
  end

  def self.sell(buy, sell)
    total = buy.total
    if (sell.quantity <= total.quantity)
      buy.sell << sell
      if (buy.total.quantity == 0)
        buy.is_open='f'
      end
      transaction(buy) do
        buy.save
      end
    end
    true
  end

  def deep_clone
    Marshal::load(Marshal.dump(self))
  end

  def addAmounts(operation)
    self.net_amount += operation.net_amount
    self.gross_amount += operation.gross_amount
    self.brokerage += operation.brokerage
  end

end
